在 MVVM 架構裡面,livedata 是個在 lifecycle 依賴包裡面非常好用也十分常用的型態之一。
其中 livedata 又分為兩種
MutableLiveData 是繼承於 LiveData 的抽象類別
package androidx.lifecycle;
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
}
liveData 類最大的特徵就是它可以在 activity 透過 observer 得知資料的改變,從而做出動作。
這次的範例是在同一個 activity 中呈現,先在 edit text 中輸入文字,按下按鈕後更改 string,以後在底下的 text view 顯示該文字,非常簡單。
一個 edit text 一個 button 一個 text view。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.MainActivity">
<EditText
android:id="@+id/editMain"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.3"/>
<Button
android:id="@+id/btnMainSave"
android:text="save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/editMain"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.2"/>
<TextView
android:id="@+id/textMainResult"
android:text="..."
android:textSize="30sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/btnMainSave"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
一樣把資料放在 repository 裡的 companion object,並用 livedata 包起來。
再用 init 方法初始化 data 為 "init",使其不為 null。
class MainRepository {
companion object{
private var data= MutableLiveData<String>()
}
init {
data.value= "init"
}
fun saveText(text: String){
data.value= text
}
fun getText() = data
}
在之前有提到,kotlin 的 getter and setter 會用成像是設定成員的值一樣
liveData 當然也是,value 就代表 liveData 裡的資料。
另外還有兩個 function 為 data 的 getter and setter。
一樣,複製一次 repository 裡的方法
class MainViewModel: ViewModel(){
private val repository= MainRepository()
fun saveText(text: String){
repository.saveText(text)
}
fun getText() = repository.getText()
}
livedata 可以用 observe 方法偵測 liveData 是否有變化,如果有變化,就執行裡面的程式碼。也就是說,我這樣寫就代表當資料改變時,將其資料顯示在該 text view 上,
class MainActivity : AppCompatActivity() {
private lateinit var edit: EditText
private lateinit var btnSave: Button
private lateinit var textResult: TextView
private val viewModel: MainViewModel by lazy {
ViewModelProvider(this, MyViewModelFactory()).get(MainViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
edit= findViewById(R.id.editMain)
btnSave= findViewById(R.id.btnMainSave)
textResult= findViewById(R.id.textMainResult)
btnSave.setOnClickListener {
viewModel.saveText(edit.text.toString())
edit.text = null
}
viewModel.getText().observe(this, Observer{
textResult.text= it
})
}
}
在 edit text 打入 "安安"
當我按下 save 的瞬間,程式會 observe 到資料有變化,就會改變底下 text view 的內容了。